#pragma once
#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace LogModule;

//模板模式  
namespace SocketModule
{
    class Socket
    {
    public:
        virtual void SocketOrDie() = 0;
        virtual void BindOrDie(uint16_t port) = 0;
        virtual void ListenOrDie(int backlog) = 0;
        virtual std::shared_ptr<TcpSocket> Accept(InetAddr* client) = 0;
        virtual void Close() = 0;
        virtual int Recv(std::string* out) = 0;
        virtual int Send(std::string& message) = 0;
        
    public:
        void Init(uint16_t port, int backlog = 16)
        {
            SocketOrDie();
            BindOrDie(port);
            ListenOrDie(backlog);
        }
    };


    class TcpSocket : public Socket
    {
    public:
            TcpSocket(){};
            TcpSocket(int fd)
                :_sockfd(fd)
            {}

        void SocketOrDie() override
        {
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                LOG(LogLevel::FATAL) << "socket error";
                exit(SOCKET_ERROR);
            }
            LOG(LogLevel::INFO) << "socket sunccess";
        }
        void BindOrDie(uint16_t port) override
        {
            InetAddr localAddr(port);
            int n = ::bind(_sockfd, localAddr.AddrPtr(), localAddr.Addrlen());
            if (n < 0)
            {
                LOG(LogLevel::FATAL) << "bind error";
                exit(BIND_ERROR);
            }
            LOG(LogLevel::INFO) << "bind sunccess";
        }
        void ListenOrDie(int backlog) override 
        {
            int n = ::listen(_sockfd, backlog);
            if (n < 0)
            {
                LOG(LogLevel::FATAL) << "listen error";
                exit(LISTEN_ERROR);
            }
            LOG(LogLevel::INFO) << "listen sunccess";
        }

        std::shared_ptr<TcpSocket> Accept(InetAddr* client) override
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int fd = ::accept(_sockfd,CONV(peer),&len);
            if(fd < 0)
                exit(ACCEPT_ERROR);
            
            //保存客户端的ip和端口信息
            client->GetAddr(peer);
            //创建一个网络文件描述符对象来管理该客户端
            return std::make_shared<TcpSocket>(fd);
        }

        int Recv(std::string* out) override
        {
            char buffer[1024];
            int n = ::recv(_sockfd,&buffer,sizeof(buffer),0);
            if(n > 0)
            {
                *out += buffer;
            }
            return n;
        }


        int Send(std::string& message) override
        {
            ::send(_sockfd,message.c_str(),message.size(),0);
        }

    private:
        int _sockfd;
    };

}
